#include <istream>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <map>
#include <boost/shared_array.hpp>
#include <stdlib.h>

#include "portable_timer.h"
#include "perlutil.h"
#include <boost/tokenizer.hpp>

using std::vector;
using std::ostringstream;
using boost::shared_array;

using std::string;
using std::fill;
using std::ofstream;
using std::cout;
using std::cin;
using std::cerr;
using std::ifstream;
using std::map;
using std::pair;
using std::istream;

struct t_ks_pairs
{
	double		ks;
	unsigned gene1;
	unsigned gene2;
	t_ks_pairs(double d, unsigned g1, unsigned g2): ks(d), gene1(g1), gene2(g2){}
};

unsigned getdata(istream& infile, vector<shared_array<double> >& matrix, vector<string>& names)
{
	vector<t_ks_pairs> ks_pairs;
	map<string, unsigned> gene_to_index;
	typedef pair<string, unsigned> t_gene_index_pair;
	string line;
	while (getline(infile, line))
	{
		if (!line.length())
		{
			// ignore consecutive blank lines
			if (!names.size())
				continue;

			// blank lines separate clusters
			else
				break;
		}

		vector<string> data;
		perl_split (line, "\t", data, false, 3);
		pair<map<string, unsigned>::iterator, bool> pr;

		unsigned tax1_index = names.size();
		pr = gene_to_index.insert(t_gene_index_pair(data[0],  tax1_index));
		if (pr.second)
			names.push_back(data[0]);
		//use existing value
		else
			tax1_index = (pr.first)->second;

		unsigned tax2_index = names.size();
		pr = gene_to_index.insert(t_gene_index_pair(data[1],  tax2_index));
		if (pr.second)
			names.push_back(data[1]);
		//use existing value
		else
			tax2_index = (pr.first)->second;

		ks_pairs.push_back(t_ks_pairs(atof(data[2].c_str()), tax1_index, tax2_index));
	}
	// number of species
	unsigned cnt_leaves = names.size();
	if (!cnt_leaves)
		return 0;

	// get data and names
	for (unsigned j = 0; j < cnt_leaves; j++)
	{
		matrix.push_back(shared_array<double>(new double [cnt_leaves]));
		fill(matrix.back().get(), matrix.back().get() + cnt_leaves, 10000.0);
	}
	for (unsigned i = 0; i < ks_pairs.size(); ++i)
		matrix[ks_pairs[i].gene1][ks_pairs[i].gene2]=
		matrix[ks_pairs[i].gene2][ks_pairs[i].gene1]= ks_pairs[i].ks;

	for (unsigned i = 0; i < matrix.size(); ++i)
		matrix[i][i]=0.0;

	return ks_pairs.size();
}  /* getdata */
/*unsigned getdata(ifstream& infile, vector<shared_array<double> >& matrix,
								vector<string>& names)
{
	vector<t_ks_pairs> ks_pairs;
	map<string, unsigned> gene_to_index;
	typedef pair<string, unsigned> t_gene_index_pair;


	// get Ks for each pair of genes
	string line;
	while (getline(infile, line))
	{
		if (!line.length())
		{
			if (names.size())
				break;
			//skip past consecutive blank lines
			else
				continue;
		}


		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
		tokenizer tokens(lines, boost::char_separator<char>("\t"));
		tokenizer::iterator tok_iter = tokens.begin();

		vector<string> data;
		perl_split (line, "\t", data, false, 3);
		pair<map<string, unsigned>::iterator, bool> pr;

		unsigned tax1_index = names.size();
		pr = gene_to_index.insert(t_gene_index_pair(*tok_iter,  tax1_index));
		if (pr.second)
			names.push_back(*tok_iter);
		//use existing value
		else
			tax1_index = (pr.first)->second;

		if (++tok_iter == tokens.end())
		{
			cerr << "Invalid data [" << line << "]\n";
			return 0;
		}

		unsigned tax2_index = names.size();
		pr = gene_to_index.insert(t_gene_index_pair(*tok_iter,  tax2_index));
		if (pr.second)
			names.push_back(*tok_iter);
		//use existing value
		else
			tax2_index = (pr.first)->second;

		if (++tok_iter == tokens.end())
		{
			cerr << "Invalid data [" << line << "]\n";
			return 0;
		}

		ks_pairs.push_back(t_ks_pairs(atof(*(tok_iter).c_str()), tax1_index, tax2_index));
	}
	// number of species
	unsigned cnt_leaves = names.size();
	if (!cnt_leaves)
		return 0;

	// get data and names
	for (unsigned j = 0; j < cnt_leaves; j++)
	{
		matrix.push_back(shared_array<double>(new double [cnt_leaves]));
		fill(matrix.back().get(), matrix.back().get() + cnt_leaves, 10000.0);
	}
	for (unsigned i = 0; i < ks_pairs.size(); ++i)
		matrix[ks_pairs[i].gene1][ks_pairs[i].gene2]=
		matrix[ks_pairs[i].gene2][ks_pairs[i].gene1]= ks_pairs[i].ks;
	return ks_pairs.size();
}
*/

int main (int argc, char *argv[])
{
	std::ios::sync_with_stdio(false);


	while (cin.good())
	{
		vector<shared_array<double> > matrix;
		vector<string> names;
		unsigned cnt_pairs =  getdata(cin, matrix, names);
		if (!cnt_pairs)
			return 1;
		unsigned expected_pairs = names.size() * (names.size() - 1) / 2;


		cerr << cnt_pairs << " out of " << expected_pairs << "\n";

		// output square matrix
		cout << names.size() << "\n";
		for (unsigned i = 0; i < names.size(); ++i)
		{
			cout << names[i] << "                 ";
			for (unsigned j = 0; j < matrix.size(); ++j)
			{
				cout << " " << matrix[i][j];
				if (matrix[i][j] > 5000.0)
					cout << " 0 ";
				else
					cout << " 1 ";
			}
			cout << "\n";
		}
		return 0;
	}


	return 0;
}


